package com.ftx.controller.test.annotation.aop;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

/**
 * Created by fengtingxin on 2020/4/27.
 *
 * AOP:[动态代理]
 *      指在程序运营期间冬天的将某段代码切入到指定方法指定位置进行运行的编程方式
 *    1.导入aop模块：Spring AOP
 *    2.定义个业务逻辑类：BusinessClass 在业务逻辑运行期间，将日志正常打印
 *    3.定义一个类的切面类(LogAspects)
 *          通知方法：
 *              前置通知(@Before)：在目标方法之前运营
 *              后置通知(@After)：在目标方法运行之后运行
 *              返回通知(@AfterReturning)：在目标方法正常返回之后运营
 *              异常通知(@AfterException)：在目标方法异常时运行
 *              环绕通知(@Around)：动态代理目标运行(joinPoint.processed())
 *    4.给切面类的目标方法标注何时何地的运行
 *    5.将切面类和业务逻辑类(目标方法所在类)都加入到容器中
 *    6.必须告诉spring哪个类是切面类(在切面类上加一个注解 @Aspect)
 *    7.给配置类加上注解@EnableAspectJAutoProxy 【开启基于注解的aop模式】
 *          在spring中有很多 @Enablexxxx就是开启功能用的
 *
 *
 *  主要把握三步：
 *      1.将业务逻辑组件和切面类放入到容器中，告诉spring哪个是切面类(@Aspect)
 *      2.在切面类上的每一个通知方法标注通知注解，告诉spring何时何地运行 (切入点表达式)
 *      3.给配置类加上注解@EnableAspectJAutoProxy 【开启基于注解的aop模式】
 *
 *
 *
 *      AOP原理：【给容器注册了什么组件，这个组件什么时候工作，这个组件工作时候的功能】
 *          @EnableAspectJAutoProxy
 *       1.@EnableAspectJAutoProxy 是什么？
 *              从源码中看到 它导入了@Import(AspectJAutoProxyRegistrar.class) 这个组件
 *          AspectJAutoProxyRegistrar 又是什么呢？ 它实现了implements ImportBeanDefinitionRegistrar
 *          ImportBeanDefinitionRegistrar 可以实现自定义注册bean到容器中
 *
 *          AspectJAutoProxyRegistrar 把bean （AnnotationAwareAspectJAutoProxyCreator）注入到spring容器中，我们看下是什么
 *          		AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
 *
 *          org.springframework.aop.config.internalAutoProxyCreator = 	AnnotationAwareAspectJAutoProxyCreator
 *          	   把 AnnotationAwareAspectJAutoProxyCreator.class (注解装配模式得切面自动代理创建器) 注入
 *
 *
 *          2.AnnotationAwareAspectJAutoProxyCreator 是什么呢？
 *              先梳理下这个类的继承关系
 *              AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator
 *                  -->AspectJAwareAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator
 *                      -->AbstractAdvisorAutoProxyCreator extends AbstractAutoProxyCreator
 *                          -->AbstractAutoProxyCreator extends ProxyProcessorSupport implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware
 *          注意这里：
 *             1）。AbstractAutoProxyCreator 中存在 postProcessAfterInitialization方法的实现 所以，是后置处理器 （在bean初始化完成之后做的事情）
 *             2）。同时它也实现了BeanFactoryAware ，自动装配BeanFactory
 *
 *           先来看 AnnotationAwareAspectJAutoProxyCreator 做了什么
 *              首先在其父类AbstractAutoProxyCreator 中，由于实现了BeanFactoryAware 所以肯定有 setBeanFactory方法
 *              AbstractAutoProxyCreator.setBeanFactory();
 *
 *              AbstractAdvisorAutoProxyCreator.setBeanFactory();  --> initBeanFactory
 *              AnnotationAwareAspectJAutoProxyCreator.initBeanFactory()
 *
 *
 *
 *
 *
 *
 *
 *  流程：
 *      1.传入配置类，创建ioc容器 ,AnnotationConfigApplicationContext的构造器
 *      2.注册配置类，调用refresh方法(刷新容器)
 *      3.registerBeanPostProcessors(beanFactory); （注册beanProcessor，拦截bean的创建）
 *          1）.获取容器中已经定义了的需要创建的所有beanPostProcessor，所有需要创建对象的BeanPostProcessor --> beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
 *          2).同时在 beanFactory 中增加其他的beanPostProcessor
 *          3).优先注册实现接口PriorityOrdered 的processor  先放到 internalPostProcessors
 *          4).再来注册Ordered接口的processor 放到orderedPostProcessorNames
 *          5).最后注册没有顺序的processor  放到 nonOrderedPostProcessorNames
 *          6).由于 org.springframework.aop.config.internalAutoProxyCreator=AnnotationAwareAspectJAutoProxyCreator 实现了ordered接口 所以放到 orderedPostProcessorNames中
 *              这里会调用getBean,但是由于这是第一次调用，所有走到了createBean，具体创建对象的地方在，doCreateBean
 *              创建org.springframework.aop.config.internalAutoProxyCreator
 *              doCreateBean 方法详细：
 *              1).创建bean实例 createBeanInstance方法
 *              2).给bean的属性赋值 populateBean方法
 *              3).初始化bean  initializeBean方法
 *                  详解：
 *                  1.invokeAwareMethods方法：；处理aware接口的初始化赋值
 *                  2.applyBeanPostProcessorsBeforeInitialization方法：
 *                  3.invokeInitMethods：执行自定义的初始化方法
 *                  4.applyBeanPostProcessorsAfterInitialization方法
 *              4).AbstractAdvisorAutoProxyCreator.setBeanFactory
 *           7).把beanPost放入beanFactory   ： registerBeanPostProcessors(beanFactory, orderedPostProcessors);
 *
 *           =======================================以上为创建AnnotationAwareAspectJAutoProxyCreator 的过程。
 *
 *
 *     4.完成beanFactory的创建工作。finishBeanFactoryInitialization(beanFactory);
 *          1.在 preInstantiateSingletons 方法中，遍历获取beanName，依次创建对象。getBean(beanName)
 *              getBean --> doGetBean  --》 getSingleton
 *          2.在doGetBean方法中：先从缓存中获取当前bean，如果能获取到，说明bean是之前被创建过的，直接使用，否则再创建
 *          3.createBean 创建bean 【AnnotationAwareAspectJAutoProxyCreator 是在bean 创建之前有个拦截，因为他实现了InstantiationAwareBeanPostProcessor ，会调用 postProcessBeforeInstantiation方法】
 *              1、【Instantiation】实例化----实例化的过程是一个创建Bean的过程，即调用Bean的构造函数，单例的Bean放入单例池中
 *              2、【initialization】初始化----初始化的过程是一个赋值的过程，即调用Bean的setter，设置Bean的属性
 *              【BeanPostProcessor 是在对象创建完成初始化前后调用的】
 *              【InstantiationAwareBeanPostProcessor 是对象在实例化前后尝试用后置处理器返回】
 *              1. resolveBeforeInstantiation(beanName, mbdToUse);
 *              Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
 *              希望后置处理器能够返回一个代理对象，如果能够返回代理对象就使用，如果不能就继续
 *                  1.applyBeanPostProcessorsBeforeInstantiation 后置处理器先尝试返回对象
 *                  2.拿到所有的beanPostProcessor ，如果后置处理器实现了InstantiationAwareBeanPostProcessor
 *                  则调用postProcessBeforeInstantiation 方法
 *
 *              2. doCreateBean(beanName, mbdToUse, args); 真正去创建一个bean实例；和 3.6流程一致
 *              3.在
 *
 *
 *       AnnotationAwareAspectJAutoProxyCreator【InstantiationAwareBeanPostProcessor】的作用：
 *       1.在每个bean创建之前，调用postProcessBeforeInstantiation方法，
 *          关心 businessClass
 *          1.判断当前bean是否在 advisedBeans(保存了增强的bean) 中
 *          2.判断当前bean是否为基础类型的advice (isInfrastructureClass 方法)
 *              Advice、Pointcut、Advisor、AopInfrastructureBean
 *              或者是否为切面(@Aspect)
 *          3.判断bean是否需要跳过  (shouldSkip方法)
 *              1.获取候选的增强器(切面里的通知方法)【List<Advisor> candidateAdvisors】
 *                  每个封装的通知方法的增强器是InstantiationModelAwarePointcutAdvisor
 *                  判断每个增强器是否为AspectJPointcutAdvisor
 *              2.返回false
 *       2.创建对象，调用到自定义的构造器方法
 *          在创建对象之后调用postProcessAfterInitialization:298, AbstractAutoProxyCreator
 *          然后调用：wrapIfNecessary:346, AbstractAutoProxyCreator
 *          1.获取当前bean的所有的额增强器（通知方法）Object[]specificInterceptors
 *              1.来获取当前bean的所有的增强器 findEligibleAdvisors
 *              2.获取能在当前bean使用的增强器
 *              3.给增强器排序
 *          2.保存当前bean在advisedBeans中
 *          3.如果当前bean需要增强，则给当前bean创建代理对象 createProxy:469, AbstractAutoProxyCreator
 *              1.把增强器放入到proxyFactory
 *              2.创建代理对象 createAopProxy:51, DefaultAopProxyFactory
 *                  选择什么代理由spring自动决定：
 *                      ObjenesisCglibAopProxy
 *                      JdkDynamicAopProxy
 *          4.给容器中返回了代理对象
 *          5.以后容器中获取到的就是这个代理对象，执行目标方法的时候，代理对象就会执行通知方法的流程。
 *
 *
 *       3.断点放在目标方法执行；容器中保存了组件的代理对象，(cglib增强后的对象)，这个对象里保存了详细的信息(比如增强器目标对象，xxx)
 *          1.intercept:643, CglibAopProxy  拦截目标方法执行
 *          2.根据ProxyFactory获取目标方法的拦截器链
 *             List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
 *              1.getInterceptorsAndDynamicInterceptionAdvice:489, AdvisedSupport
 *                  创建 List<Object> interceptorList  长度为 5
 *                  一个默认的：ExposeInvocationInterceptor.ADVISOR 和 自定义的4个增强器
 *              2.advisor 转为interceptors  registry.getInterceptors(advisor);
 *              把advisor都转为 methodInterceptor ，变成一个拦截器链
 *          3.如果没有拦截器链，直接执行目标方法
 *          4.如果有拦截器链,	 retVal =new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
 *              这里会直接调用proceed方法执行
 *                  proceed方法详细分析：proceed:156, ReflectiveMethodInvocation
 *                      1.如果没有拦截器直接执行目标方法，或者拦截器的索引和拦截器数组-1一样(指定到最后一个拦截器，执行目标方法)
 *                          1.currentInterceptorIndex 从-1 开始
 *                          Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
 *                          获取第0个拦截器， 	interceptorOrInterceptionAdvice = ExposeInvocationInterceptor
 *                          执行invoke 方法((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
 *                          2.++currentInterceptorIndex 1
 *                              AspectJAfterThrowingAdvice
 *                          3.++currentInterceptorIndex 2
 *                              AspectJAfterReturningAdvice
 *                          4.++currentInterceptorIndex 3
 *                              org.springframework.aop.aspectj.AspectJAfterAdvice
 *                          5.++currentInterceptorIndex 4
 *                              org.springframework.aop.aspectj.AspectJMethodBeforeAdvice
 *                                  1.调用前置通知：		this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
 *
 *                          6.返回
 *                              执行当前方法
 *
 *
 *          5.拦截器链触发过程：
 *              1.如果没有拦截器直接执行目标方法，或者拦截器的索引和拦截器数组的-1大小一样，（指定到了最后一个拦截器）执行目标方法
 *              2.链式获取每一个拦截器，拦截器执行invoke方法，每一个拦截器等待下一个拦截器执行完成返回以后再来执行。
 *                  拦截器链的机制，保证通知方法与目标方法的执行顺序
 *
 *
 *
 *  总结：
 *      1.@EnableAspectJAutoProxy 利用这个注解开启aop
 *      2.@EnableAspectJAutoProxy会给容器中注册一个组件 AnnotationAwareAspectJAutoProxyCreator
 *      3.AnnotationAwareAspectJAutoProxyCreator 是一个后置处理器
 *      4.容器的创建流程：
 *          1.registerBeanPostProcessors() 注册后置处理器，创建AnnotationAwareAspectJAutoProxyCreator
 *          2.finishBeanFactoryInitialization()处理化剩下的单实例bean
 *              1.创建业务逻辑组件和切面组件
 *              2.AnnotationAwareAspectJAutoProxyCreator拦截组件的创建过程
 *              3.组件创建完成之后，判断组件是否需要增强：postProcessAfterInitialization
 *                  是：切面的通知方法包装为增强器(Advisor),给业务逻辑组件创建一个代理对象(cglib)
 *      5.要执行目标方法
 *          1.代理对象执行目标方法
 *          2.intercept:643, CglibAopProxy  拦截目标方法执行
 *              1.得到目标方法的拦截器链(增强器包装成拦截器methodInterceptor)
 *              2.利用拦截器的链式机制，依次进入每一个拦截器进行执行
 *              3.效果：
 *                  正常执行：前置通知-->目标方法-->后置通知-->返回通知
 *                  异常执行：前置通知-->目标方法-->后置通知-->异常通知
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

@EnableAspectJAutoProxy
@Configuration
public class MainConfigOfAop {


    @Bean
    public BusinessClass businessClass(){
        return new BusinessClass();
    }

    @Bean
    public LogAspects logAspects(){
        return new LogAspects();
    }
}
